#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#undef min
#undef max
#include <EGL/egl.h>
#include <iostream>

#include "Application.h"
#include "platformspecific.h"

EGLDisplay g_eglDisplay = NULL;
EGLSurface g_eglSurface = NULL;

HINSTANCE g_windows__applicationInstanceHandle = NULL;
HWND g_windows__windowHandle = NULL;
const int c_width = 360;
const int c_height = 640;
const TCHAR* c_title = __TEXT("OpenGL ES 2.0");
const TCHAR* c_className = __TEXT("GLES2WINDOWCLASS");

namespace
{
	LRESULT
	CALLBACK
	windows__callback(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam)
	{
		switch(message)
		{

		case WM_KEYDOWN:
			break;

		case WM_CHAR:
			break;

		case WM_CREATE:
			break;

		case WM_CLOSE:
//			return 0;
			break;

		case WM_MOUSEWHEEL:
			break;
			
		case WM_SIZE:
			break;

		default:
			break;
		}

		return (DefWindowProc(windowHandle, message, wParam, lParam));
	}
}

void
platform_break(const std::string& message)
{
	std::ostringstream ss;
	ss << "Message:\n" << message << "\n\nDo you want to ignore it and continue?";

	int reply = MessageBoxA(g_windows__windowHandle, ss.str().c_str(), "An error has occured", MB_ICONERROR | MB_YESNO);
	if (reply == IDNO)
	{
		DebugBreak();
	}
}

EGLNativeWindowType
createWindow()
{
	DWORD extendedWindowStyle;
	DWORD windowStyle;
	RECT windowRect;

	windowRect.top = 0;
	windowRect.left = 0;
	windowRect.bottom = c_height;
	windowRect.right = c_width;

	extendedWindowStyle = NULL;
	windowStyle =	WS_OVERLAPPEDWINDOW |
					WS_VISIBLE |
					WS_SYSMENU |
					WS_CLIPCHILDREN |
					WS_CLIPSIBLINGS;

	AdjustWindowRectEx(&windowRect, windowStyle, false, extendedWindowStyle);
	windowRect.bottom -= windowRect.top;
	windowRect.right -= windowRect.left;
	windowRect.left = 0;
	windowRect.top = 0;

	g_windows__windowHandle = CreateWindowEx(extendedWindowStyle,
					c_className,
					c_title,
					windowStyle,
					windowRect.left, windowRect.top,
					windowRect.right, windowRect.bottom,
					NULL,
					NULL,
					g_windows__applicationInstanceHandle,
					NULL);

	if (g_windows__windowHandle != NULL)
	{
		ShowWindow(g_windows__windowHandle, SW_SHOW);
		UpdateWindow(g_windows__windowHandle);
	}
			
	return g_windows__windowHandle;
}

void
initGL()
{
	EGLNativeWindowType eglWindow = createWindow();

	g_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	PLATFORM_ASSERT(g_eglDisplay != EGL_NO_DISPLAY, "Failed to get EGL Display");

	EGLint major;
	EGLint minor;
	EGLBoolean eglInitOk = eglInitialize(g_eglDisplay, &major, &minor);
	PLATFORM_ASSERT(eglInitOk, "Failed to initialize EGL");

	const EGLint attributeList[] =
	{
		EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 
		EGL_NONE 
	};
	EGLConfig bestConfig;
	EGLint numConfigs = 0;

	if (eglChooseConfig(g_eglDisplay, attributeList, &bestConfig, 1, &numConfigs) == EGL_FALSE)
	{
		PLATFORM_BREAK("Failed to choose config");
	}

	g_eglSurface = eglCreateWindowSurface(g_eglDisplay, bestConfig, eglWindow, NULL);
	if (g_eglSurface == NULL)
	{
		PLATFORM_BREAK("eglCreateWindowSurface failed");
	}
        
	// Create a rendering context
	EGLContext eglContext = eglCreateContext(g_eglDisplay, bestConfig, EGL_NO_CONTEXT, NULL);
	if (eglContext == NULL)
	{
		PLATFORM_BREAK("eglCreateContext failed");
	}
    
	// Make it the current context.
	if (eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, eglContext) == EGL_FALSE)
	{
		PLATFORM_BREAK("eglMakeCurrent failed");
	}
}

void
main()
{
	initGL();

	Application application;
	application.init();

	bool exit = false;
	while (!exit)
	{
		MSG msg;

		while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				exit = true;
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		application.update(0.01f);
		application.render();
		eglSwapBuffers(g_eglDisplay, g_eglSurface);
	}

	application.deinit();
}

int
WINAPI
WinMain(HINSTANCE instance, HINSTANCE prevInstance, char *lpzCommandLine, int iShow)
{
	g_windows__applicationInstanceHandle = instance;

    TCHAR filename[_MAX_PATH];
    
    GetModuleFileName(NULL, filename, _MAX_PATH);

	AllocConsole();
	SetConsoleTitle(filename);
	freopen("CONIN$","rb",stdin);
	freopen("CONOUT$","wb",stdout);
	freopen("CONOUT$","wb",stderr);

	WNDCLASSEX windowClass;
	windowClass.cbSize			= sizeof(WNDCLASSEX);	
	windowClass.style			= CS_HREDRAW | CS_VREDRAW;
	windowClass.lpfnWndProc		= windows__callback;
	windowClass.cbClsExtra		= 0;
	windowClass.cbWndExtra		= 0;
	windowClass.hInstance		= g_windows__applicationInstanceHandle;
	windowClass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	windowClass.hCursor			= LoadCursor(NULL, IDC_ARROW);
	windowClass.hbrBackground	= NULL;
	windowClass.lpszMenuName	= NULL;
	windowClass.lpszClassName	= c_className;
	windowClass.hIconSm			= LoadIcon(NULL,IDI_APPLICATION);

	if (!RegisterClassEx(&windowClass))
	{
		return NULL;
	}

	main();

	if (g_windows__windowHandle != NULL)
	{
		DestroyWindow(g_windows__windowHandle);
	}

	UnregisterClass(c_className, g_windows__applicationInstanceHandle);

	FreeConsole();

	return 0;
}
